package ui.panels.strategies.manual;

import gameEngine.agents.choosingStrategy.SelectWorstStrategy;
import gameEngine.agents.choosingStrategy.representation.EGreedyRepresentation;
import gameEngine.agents.choosingStrategy.representation.GreedyRepresentation;
import gameEngine.agents.choosingStrategy.representation.ManuallAdaptiveRepresentation;
import gameEngine.agents.choosingStrategy.representation.RoundRobinRepresentation;
import gameEngine.agents.choosingStrategy.representation.SelectWorstRepresentation;
import gameEngine.agents.choosingStrategy.representation.SimpleRandomRepresentation;
import gameEngine.agents.choosingStrategy.representation.StrategyRepresentation;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.DefaultCellEditor;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.LayoutStyle;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;

import org.apache.log4j.Logger;

import auxiliary.AuxiliaryClass;

import ui.flowManager.FlowManagerImpl;
import ui.flowManager.expirimentProperties.AgentRepresentation;
import ui.flowManager.expirimentProperties.ExperimentProperties.Agent_Group;
import ui.panels.commands.SetEnablecommand;
import ui.panels.commands.SetStrategyRepresentationCommand;
import ui.panels.strategies.StrategyFrame;

import Data.ConfigurationParameters;


/**
 * @author vladimir && alon
 *
 *	Panel for manual adaptive strategy 
 */
public class ManualPanel extends JPanel{

	Logger log = Logger.getLogger(this.getClass());
	
	List<TableCellEditor> 		editors = new ArrayList<TableCellEditor>();
    private int 				numRows = 0;
    private JTable 				table = null;
    private JScrollPane 		scrollPane = null;
    private DefaultTableModel 	model = null;
    
    private  JComboBox 			strategyComboBox = null; 
    DefaultCellEditor 			defaultCellEditor=null;
    
    private JButton 			addStrategy = null;
    private JButton 			Ok = null;
    private JButton 			cancel = null;

    private  StrategyFrame	 	myFrame = null;		
	private int 				gameNumber = 0;
	private int 				playerNumber = 0;
	private int					turnsInGame = 0;

    {
		//Set Look & Feel
		try {
			javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	public ManualPanel(StrategyFrame frame, int gameNumber, int plyerNumber, int turns)
	{
		super();
		this.myFrame = frame; 
		this.gameNumber = gameNumber;
		this.playerNumber = plyerNumber;
		this.turnsInGame = turns;
		
		initGUI();
	}
	
	private void initGUI() {
        // Create the editors to be used for each row

		initializeComboBox();
	
        //  Create the table with default data
        Object[][] data =
        {
           // {ConfigurationParameters.Strategy.EGREEDY, "0"}
        };
        
        String[] columnNames = {"Strategy","Turns"};
        
        try {
			GroupLayout thisLayout = new GroupLayout((JComponent)this);
			this.setLayout(thisLayout);
			setPreferredSize(new Dimension(400, 300));

	        model = new DefaultTableModel(data, columnNames);
	        

	        table = new JTable(model)
	        {
	            //  Determine editor to be used by row
	            public TableCellEditor getCellEditor(int row, int column)
	            {
	                int modelColumn = convertColumnIndexToModel( column );

	                if (modelColumn == 0 && row < numRows)
                		return editors.get(row);
	                else
	                    return super.getCellEditor(row, column);
	            }     
	        };
		       
	        table.getColumnModel().getColumn(0).setPreferredWidth(100);
	        table.getColumnModel().getColumn(1).setPreferredWidth(25);
	        
	        JScrollPane scrollPane = new JScrollPane( table );
	        {
	        	addStrategy  = new JButton();
	        	addStrategy .setText("+");
	        }
	        {
	        	Ok = new JButton();
	        	Ok.setText("OK");
	        }
	        {
	        	cancel = new JButton();
	        	cancel.setText("Cancel");
	        }
			thisLayout.setVerticalGroup(thisLayout.createSequentialGroup()
				.addContainerGap(44, 44)
				.addGroup(thisLayout.createParallelGroup()
				    .addGroup(thisLayout.createSequentialGroup()
				        .addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 229, GroupLayout.PREFERRED_SIZE)
				        .addGap(0, 0, Short.MAX_VALUE))
				    .addGroup(GroupLayout.Alignment.LEADING, thisLayout.createSequentialGroup()
				        .addComponent(addStrategy, GroupLayout.PREFERRED_SIZE, 63, GroupLayout.PREFERRED_SIZE)
				        .addGap(0, 77, Short.MAX_VALUE)
				        .addComponent(Ok, GroupLayout.PREFERRED_SIZE, 35, GroupLayout.PREFERRED_SIZE)
				        .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				        .addComponent(cancel, GroupLayout.PREFERRED_SIZE, 35, GroupLayout.PREFERRED_SIZE)
				        .addGap(7)))
				.addContainerGap(27, 27));
			thisLayout.setHorizontalGroup(thisLayout.createSequentialGroup()
				.addContainerGap(18, 18)
				.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 241, GroupLayout.PREFERRED_SIZE)
				.addGap(17)
				.addGroup(thisLayout.createParallelGroup()
				    .addGroup(thisLayout.createSequentialGroup()
				        .addComponent(addStrategy, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
				        .addGap(0, 0, Short.MAX_VALUE))
				    .addGroup(thisLayout.createSequentialGroup()
				        .addPreferredGap(addStrategy, Ok, LayoutStyle.ComponentPlacement.INDENT)
				        .addGroup(thisLayout.createParallelGroup()
				            .addComponent(Ok, GroupLayout.Alignment.LEADING, 0, 94, Short.MAX_VALUE)
				            .addGroup(thisLayout.createSequentialGroup()
				                .addComponent(cancel, GroupLayout.PREFERRED_SIZE, 94, GroupLayout.PREFERRED_SIZE)
				                .addGap(0, 0, Short.MAX_VALUE)))))
				.addContainerGap(24, 24));

		} catch (Exception e) {
			log.debug(e.toString());
		}
		
		//Set the listeners in the components
        setListeners();
        
        //case the player initialized
        if (playerNumber > 0)
        {
        	setStrategies();
        }
        
	}
	
	
	/**
	 * Add Row to the table 
	 */
	public void addRow(String strategyName)
	{
		//find the number of turns that remain in the game
        int turns = turnsRemain();
        String turnsStr = Integer.toString(turns);
        addInitializedRow(strategyName, turnsStr);
	}
	
	
	public JButton getAddStrategy() {
		return addStrategy;
	}

	public JButton getOk() {
		return Ok;
	}

	public JButton getCancel() {
		return cancel;
	}
	
	public int getNumRows() {
		return numRows;
	}

	public DefaultTableModel getModel() {
		return model;
	}
	
	public JTable getTable() {
		return table;
	}

	/**
	 * Create && return representation for strategy
	 * @param name
	 * @return strategyRepresentation
	 */
	public StrategyRepresentation createStrategyRepresentation(String name)
	{
		StrategyRepresentation strategyRepresentation = null;
		
		if(name.equals(ConfigurationParameters.Strategy.EGREEDY))
		{
			strategyRepresentation= new 
						EGreedyRepresentation(ConfigurationParameters.Strategy.EGREEDY);
		}	
		else if(name.equals(ConfigurationParameters.Strategy.GREEDY))
		{
			strategyRepresentation = new
				GreedyRepresentation(ConfigurationParameters.Strategy.GREEDY);
		}
		else if(name.equals(ConfigurationParameters.Strategy.ROUND_ROBIN))
		{
			strategyRepresentation = new
				RoundRobinRepresentation(ConfigurationParameters.Strategy.ROUND_ROBIN);
		}
		else if(name.equals(ConfigurationParameters.Strategy.SELECT_WORST))
		{
			strategyRepresentation = new 
				SelectWorstRepresentation(ConfigurationParameters.Strategy.SELECT_WORST);
		}
		else if(name.equals(ConfigurationParameters.Strategy.SIMPLE_RANDOM))
		{
			strategyRepresentation = new 
				SimpleRandomRepresentation(ConfigurationParameters.Strategy.SIMPLE_RANDOM);
		}
		
		return strategyRepresentation;
	}
	
	
	/***
	 * Set the listeners in the components
	 * Components:
	 * 		addStrategy button
	 */
	private void setListeners()
	{
		ManualListener actionListener = new ManualListener(this);
		
		addStrategy.addActionListener(actionListener);
		Ok.addActionListener(actionListener);		
		cancel.addActionListener(actionListener);				
	}
	
	/**
	 * Enable the prime GUI && close this panel frame
	 */
	public void setEnablePrimePanelAndClose()
	{
		//set enable the prime GUI , use via command pattern
		SetEnablecommand enableCommand = new SetEnablecommand();
		enableCommand.setArg(true);
		enableCommand.execute();
		//close the manual panel
		myFrame.dispose();
	}
	
	/**
	 * Initialize the strategies that in the table drop box
	 */
	private void initializeComboBox()
	{	
		String[] strategies = {ConfigurationParameters.Strategy.EGREEDY,
								ConfigurationParameters.Strategy.GREEDY,
								ConfigurationParameters.Strategy.ROUND_ROBIN,
								ConfigurationParameters.Strategy.SELECT_WORST,
								ConfigurationParameters.Strategy.SIMPLE_RANDOM};
		
	    strategyComboBox = new JComboBox( strategies );
        defaultCellEditor = new DefaultCellEditor(strategyComboBox);
        editors.add(defaultCellEditor);	
        
        numRows = 0;
	}
	
	
	private void setStrategies()
	{
		//first check if previous strategy was also manual	
		AgentRepresentation agRepresentation = FlowManagerImpl.
				getInstance().getProps().getPlayer(gameNumber, playerNumber, Agent_Group.CONTROL_AGENT);
		
		StrategyRepresentation strRepresentation = agRepresentation.getStrategyType();		
		//case not manual
		if(!(strRepresentation instanceof ManuallAdaptiveRepresentation))
		{
			return;
		}
		//cast to manual
		ManuallAdaptiveRepresentation manualRepresentation = (ManuallAdaptiveRepresentation) strRepresentation;
		int numStrategies = manualRepresentation.numberOfStrategies();
		//take the strategies and put them to table
		for (int i = 0; i < numStrategies; ++i)
		{
			StrategyRepresentation strategy = manualRepresentation.getStrategy(i + 1);
			int turns = manualRepresentation.getNumberTurns(i + 1);
			String turnsStr = Integer.toString(turns);
			//add to table
			addInitializedRow(strategy.getStrategyName(), turnsStr);
		}		
	}

	private void addInitializedRow(String strategyName, String turns)
	{
		Vector<String> vec = new Vector<String>();
	    vec.add(strategyName);
        vec.add(turns);
        model.addRow(vec);
        //have to add cell !!!
        editors.add(defaultCellEditor);
        ++numRows;
	}
	



	/**
	 * Calculate number of turns that can be use in next strategy
	 * @return turns that remain 
	 */
	private int turnsRemain()
	{
		int totalTurns  = 0;
		//go over the table and count the turns that was sset
		for(int i = 0; i < numRows; ++i)
		{
			//number of turns
			String turnsStr = (String) model.getValueAt(i, 1);
			 if(AuxiliaryClass.isNumber(turnsStr))
			 {
				 totalTurns = totalTurns + Integer.parseInt(turnsStr);
			 }
		}
		
		return turnsInGame - totalTurns;
	}
	
	
}
